/**
https://reactjs.org/docs/hooks-overview.html#effect-hook

您以前可能执行过数据获取、订阅或手动更改React组件中的DOM。我们称这些操作为副作用(或者简称为效果)，因为它们会影响其他组件，并且不能在渲染期间完成。
You’ve likely performed data fetching, subscriptions, or manually changing the DOM from React components before. We call these operations “side effects” (or “effects” for short) because they can affect other components and can’t be done during rendering.

Effect Hook, useEffect，增加了从函数组件执行副作用的能力。它的作用与React类中的componentDidMount、componentDidUpdate和componentWillUnmount相同，但统一为一个API。
The Effect Hook, useEffect, adds the ability to perform side effects from a function component. It serves the same purpose as componentDidMount, componentDidUpdate, and componentWillUnmount in React classes, but unified into a single API.


使用 useEffect 完成副作用操作。赋值给 useEffect 的函数会在组件渲染到屏幕之后执行。
When you call useEffect, you’re telling React to run your “effect” function after flushing changes to the DOM

不是以mounting和updating来思考,而是用 "after render" 来思考副作用,你会发现这样更简单. React确保DOM已经更新完毕，当这些副作用执行的时候。
Instead of thinking in terms of “mounting” and “updating”, you might find it easier to think that effects happen “after render”.React guarantees the DOM has been updated by the time it runs the effects.
*/

import React, {useEffect, useState} from 'react';
import ReactDOM from 'react-dom';

/*class Counter extends React.Component {
    state = {number: 0}
    componentDidMount(): void {
        //@ts-ignore
        document.title = this.state.number;
    }

    componentDidUpdate(){
        //@ts-ignore
        document.title = this.state.number;
    }

    render(){
        return (
            <div>
                <p>{this.state.number}</p>
                <button onClick={()=>this.setState({number:this.state.number+1})}>+</button>
            </div>
        )
    }
}*/

function Counter(){
  const [state, setState] = useState({number: 0});

  //useEffect里的函数会在组件挂载完成后,或则组件更新完成后进行调用
  /*
    如果没有给第二个参数 ↑函数会在每次执行渲染后调用
    而如果是空数组 则只会在组件挂载完成执行一次后就不再执行了
  */
  /** ↓你可以把它当做"afterRender",即渲染完成后(渲染到屏幕上了),会调用的钩子*/
  useEffect(() => {
    //@ts-ignore
    // document.title = state.number // 这一行就等于上面被注释的两个生命周期(componentDidMount、componentDidUpdate)里执行该函数

    console.log('开始一个定时器');
    //↓注意如果依赖的不是空数组 定时器就可能被叠加执行
    const timer = setInterval(() => {
      setState(x => ({number: x.number + 1}))
    }, 1000);

    //useEffect会返回一个清理函数,当组件将要卸载的时候会执行清理函数
    //如果不使用useEffect的第二个参数(即deps中我们不设置`[]`)
    //则每次Counter函数调用时 都会先执行↓下面return的函数 (除了组件刚mounted时)
    //然后再执行useEffect的函数
    // (意思是每次渲染都会先销毁上一个设置的定时器,然后再开启一个新的定时器,console里我们可以看到会先打印 '销毁一个定时器' 然后跟着打印 '开始一个定时器')
    //没错这种情况会先执行return的函数 然后才会执行回调
    //另外↓这个函数 也会在组件销毁时单独执行
    return () => {
      console.log('销毁一个定时器');
      clearInterval(timer);
    };
  });

  console.log('准备render'); /** ←会先于useEffect执行*/

  return (
    <div>
      <p>{state.number}</p>
      <button onClick={() => setState({number: state.number + 1})}>+</button>
    </div>
  );
}

export default function App(){
  const [visible, setVisible] = useState(true);
  //点击会销毁Counter
  return (
    <div>
      <button onClick={()=>setVisible(false)}>hide</button>
      {visible && <Counter/>}
    </div>
  )
}
